package service

import (
	"encoding/json"
	"fmt"
	"gitee.com/csingo/cHTTPClient"
	"gitee.com/csingo/cHelper"
	"gitee.com/csingo/cLog"
	"github.com/gin-gonic/gin"
	"io/ioutil"
	"os"
	"path/filepath"
	"satis-go/base/collector"
	"satis-go/config/vars"
	"strings"
	"time"
)

type PackagistService struct {
	collector.PackagistServiceHTTPServer
}

func (i *PackagistService) Download(ctx *gin.Context, req *collector.PackagistServiceDownloadReq) (rsp *collector.PackagistServiceDownloadRsp, err error) {
	rsp = &collector.PackagistServiceDownloadRsp{
		Versions:        []string{},
		IsUpdateVersion: false,
	}
	cLog.WithContext(ctx, map[string]interface{}{
		"req": req,
	}).Debug("PackagistService.Download:start")
	// 下载json
	packageJsonDownloadUrl := fmt.Sprintf("%s/packages/%s.json", req.Url, req.Name)
	_, jsonBody, err := cHTTPClient.Request(cHTTPClient.Option{
		Host:    packageJsonDownloadUrl,
		Method:  cHTTPClient.MethodGET,
		Timeout: 60 * time.Second,
	})
	if err != nil {
		cLog.WithContext(ctx, map[string]interface{}{
			"req": req,
			"err": err.Error(),
		}).Error("PackagistService.Download:下载json失败")
		return
	} else {
		cLog.WithContext(ctx, map[string]interface{}{
			"req":                    req,
			"packageJsonDownloadUrl": packageJsonDownloadUrl,
		}).Debug("PackagistService.Download:读取json成功")
	}

	// 解析json
	sourcePackage := &collector.SourcePackages{}
	err = json.Unmarshal(jsonBody, sourcePackage)
	if err != nil {
		cLog.WithContext(ctx, map[string]interface{}{
			"req": req,
			"err": err.Error(),
		}).Error("PackagistService.Download:json解析失败")
		return
	}

	// 生成include
	includePackages := &collector.IncludePackages{
		Packages: map[string]map[string]interface{}{
			req.Name: sourcePackage.Package.Versions,
		},
	}
	includePackagesJsonBody, err := json.Marshal(includePackages)
	if err != nil {
		cLog.WithContext(ctx, map[string]interface{}{
			"req": req,
			"err": err.Error(),
		}).Error("PackagistService.Download:include json格式化失败")
		return
	}
	includePackagesJsonContent := string(includePackagesJsonBody)

	// 生成p2
	p2Packages := &collector.P2Packages{
		Packages: map[string][]interface{}{
			req.Name: {},
		},
	}
	for _, item := range sourcePackage.Package.Versions {
		p2Packages.Packages[req.Name] = append(p2Packages.Packages[req.Name], item)
	}
	p2PackagesJsonBody, err := json.Marshal(p2Packages)
	if err != nil {
		cLog.WithContext(ctx, map[string]interface{}{
			"req": req,
			"err": err.Error(),
		}).Error("PackagistService.Download:p2 json格式化失败")
		return
	}
	p2PackagesJsonContent := string(p2PackagesJsonBody)

	// 下载压缩包
	cLog.WithContext(ctx, map[string]interface{}{
		"req": req,
	}).Debug("PackagistService.Download:开始下载压缩包")
	result := []string{}
	for name, item := range sourcePackage.Package.Versions {
		result = append(result, name)
		// 从interface中提取下载url
		pkg := &collector.PackageDetail{}
		pkgJsonBody, err := json.Marshal(item)
		if err != nil {
			cLog.WithContext(ctx, map[string]interface{}{
				"req": req,
				"err": err.Error(),
			}).Error("PackagistService.Download:下载压缩包json格式化失败")
			return rsp, err
		}
		err = json.Unmarshal(pkgJsonBody, pkg)
		if err != nil {
			cLog.WithContext(ctx, map[string]interface{}{
				"req": req,
				"err": err.Error(),
			}).Error("PackagistService.Download:下载压缩包json解析失败")
			return rsp, err
		}
		// 构造路径
		filename := fmt.Sprintf("%s-%s.%s", strings.ReplaceAll(req.Name, "/", "-"), pkg.Dist.Reference, pkg.Dist.Type)
		pkgPath := filepath.Clean(fmt.Sprintf("%s/dist/%s/%s", vars.CollectorConfig.PackagesPath, req.Name, filename))
		pkgDir := filepath.Dir(pkgPath)
		if !cHelper.IsExistsPath(pkgDir) {
			err = os.MkdirAll(pkgDir, 0755)
			if err != nil {
				cLog.WithContext(ctx, map[string]interface{}{
					"req": req,
					"pkg": pkg,
					"dir": pkgDir,
					"err": err.Error(),
				}).Error("PackagistService.Download:创建dist目录失败")
				return rsp, err
			}
		}
		if !cHelper.IsExistsPath(pkgPath) {
			// 执行下载
			_, downloadBody, err := cHTTPClient.Request(cHTTPClient.Option{
				Host:    pkg.Dist.Url,
				Method:  cHTTPClient.MethodGET,
				Timeout: 1 * time.Minute,
			})
			if err != nil {
				cLog.WithContext(ctx, map[string]interface{}{
					"req": req,
					"pkg": pkg,
					"err": err.Error(),
				}).Error("PackagistService.Download:下载压缩包失败")
				return rsp, err
			} else {
				cLog.WithContext(ctx, map[string]interface{}{
					"req":     req,
					"url":     pkg.Dist.Url,
					"pkgPath": pkgPath,
				}).Debug("PackagistService.Download:下载压缩包成功")
			}
			// 写压缩包文件
			err = ioutil.WriteFile(pkgPath, downloadBody, 0755)
			if err != nil {
				cLog.WithContext(ctx, map[string]interface{}{
					"req":  req,
					"pkg":  pkg,
					"dir":  pkgDir,
					"path": pkgPath,
					"err":  err.Error(),
				}).Error("PackagistService.Download:写dist文件失败")
				return rsp, err
			}
		}

		// 替换下载url
		newDistUrl := fmt.Sprintf("%s/dist/%s/%s", vars.CollectorConfig.SatisHost, req.Name, filename)
		includePackagesJsonContent = strings.ReplaceAll(includePackagesJsonContent, pkg.Dist.Url, newDistUrl)
		p2PackagesJsonContent = strings.ReplaceAll(p2PackagesJsonContent, pkg.Dist.Url, newDistUrl)

		rsp.IsUpdateVersion = true
	}

	// 写include文件
	includePath := filepath.Clean(fmt.Sprintf("%s/include/%s.json", vars.CollectorConfig.PackagesPath, req.Name))
	includeDir := filepath.Dir(includePath)
	if !cHelper.IsExistsPath(includeDir) {
		err = os.MkdirAll(includeDir, 0755)
		if err != nil {
			cLog.WithContext(ctx, map[string]interface{}{
				"req": req,
				"dir": includeDir,
				"err": err.Error(),
			}).Error("PackagistService.Download:创建include目录失败")
			return
		}
	}
	err = ioutil.WriteFile(includePath, []byte(includePackagesJsonContent), 0755)
	if err != nil {
		cLog.WithContext(ctx, map[string]interface{}{
			"req":  req,
			"path": includePath,
			"err":  err.Error(),
		}).Error("PackagistService.Download:写include文件失败")
		return
	} else {
		cLog.WithContext(ctx, map[string]interface{}{
			"req":  req,
			"path": includePath,
		}).Debug("PackagistService.Download:写include文件成功")
	}

	// 写p2文件
	p2Path := filepath.Clean(fmt.Sprintf("%s/p2/%s.json", vars.CollectorConfig.PackagesPath, req.Name))
	p2Dir := filepath.Dir(p2Path)
	if !cHelper.IsExistsPath(p2Dir) {
		err = os.MkdirAll(p2Dir, 0755)
		if err != nil {
			cLog.WithContext(ctx, map[string]interface{}{
				"req": req,
				"dir": p2Dir,
				"err": err.Error(),
			}).Error("PackagistService.Download:创建p2目录失败")
			return
		}
	}
	err = ioutil.WriteFile(p2Path, []byte(p2PackagesJsonContent), 0755)
	if err != nil {
		cLog.WithContext(ctx, map[string]interface{}{
			"req":  req,
			"path": p2Path,
			"err":  err.Error(),
		}).Error("PackagistService.Download:写p2文件失败")
		return
	} else {
		cLog.WithContext(ctx, map[string]interface{}{
			"req":  req,
			"path": p2Path,
		}).Debug("PackagistService.Download:写p2文件成功")
	}

	cLog.WithContext(ctx, nil).Debug("PackagistService.Download:end")
	rsp.Versions = result

	return
}
